#include "stofac.h"


#define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
#define min( a, b ) ( ((a) < (b)) ? (a) : (b) )


/* Refer to lpex8: setproblemdata */
int DZpopulatemod(CPXENVptr env, CPXLPptr lp, int ni, int ns, double eps)
{
  int i,j,k;
  int status;
  int nrows = ni * ns + 1;
  int ncols = ni + ns;
  char *rowname[nrows];
  char *colname[ncols];
  char truerowname[nrows][10];
  char truecolname[ncols][10];
  for(i = 0; i< nrows; i++) rowname[i] = truerowname[i];
  for(i = 0; i< ncols; i++) colname[i] = truecolname[i];
  char sense[nrows];
  char xctype[ncols];
  
  double *prbb = (double *)malloc(ns * sizeof(double));
  double *cost = (double *)malloc(ni * sizeof(double));
  double *obj  = (double *)malloc(ncols * sizeof(double));
  double *lb   =  (double *)malloc(ncols * sizeof(double));
  double *ub   =  (double *)malloc(ncols * sizeof(double));
  double *rhs  = (double *)malloc(nrows * sizeof(double));

  int zero = 0;  //should be zero
  int y_ind[ns];

  for(i = 0; i < ni; i++)   cost[i] = runif(5, 10);       //to be changed later on
  for(i = 1; i < nrows; i++) rhs[i] = runif(5, 10);       //to be changed to random later on //used to be -runif(1,10)
  rhs[0] = eps;

  /* First create the columns */
  for(i = 0; i < ncols; i++)
    {
      if(i < ni)
        {
          sprintf(colname[i], "x_%d", i);
          lb[i] = 0.0;
	  ub[i] = CPX_INFBOUND;
	  //ub[i] = 10000.0;
          obj[i] = cost[i]; 
          xctype[i] = 'C';
        }
      else
        {
          sprintf(colname[i], "y_%d", i-ni);
          lb[i] = 0.0;
          ub[i] = 1.0;
          obj[i] = 0;  //should be zero here ,but we hack it.
          xctype[i] = 'B';
        }
    }

  status = CPXnewcols(env, lp, ncols, obj, lb, ub, xctype, colname);
  if(status) return status;

  for(i = 0; i < ns; i++)      y_ind[i] = ni + i;
  for(i = 0; i < ns; i++)       prbb[i] = 1.0 / ns;  //equal probability

  /* Add the knapsack constraint */
  status = CPXaddrows(env, lp, 0, 1, ns, &eps, "L", &zero, y_ind, prbb, NULL, NULL);
  if(status) return status;

  int row_id;
  int xy_ind[2];
  double xy_val[2];
  //  printf("ni %i, ns %i\n", ni, ns);
  /* Add rest of the constraints */
  for(j = 0; j < ns; j++)
    { 
      for(i = 0; i < ni; i++)
        {
          row_id = 1 + j*ni + i;
          xy_ind[0] = i;
          xy_ind[1] = ni + j;
          xy_val[0] = 1; 
          xy_val[1] = rhs[row_id]; //to be changed
	    //= 0.1*rhs[row_id];
	    //rhs[row_id] + 1e-5; //to be changed
          // printf("add rhs[%i] : %f\n", row_id, rhs[row_id]);
          /* Add the demand constraint */
          status = CPXaddrows(env, lp, 0, 1, 2, &rhs[row_id], "G", &zero, xy_ind, xy_val, NULL, NULL);
        }
    }
 
  free(prbb);
  free(cost);
  free(obj);
  free(lb);
  free(ub);
  free(rhs);
  return 0;
}


int DZgetbigmind(CPXENVptr env, CPXLPptr lp, int **bigmrowind_p, int **bigmcolind_p, int **bigmchgind_p)
{
  int i,j;
  int *zbigmrowind = NULL;
  int *zbigmcolind = NULL;
  int *zbigmchgind = NULL;
  double *zbigmval = NULL;
  int status;
  int nrows = CPXgetnumrows(env, lp);
  int ncols = CPXgetnumcols(env, lp);
  int nbin =  CPXgetnumbin(env, lp);
  int ncon =  ncols - nbin;
  int nbigm = nrows - 1;

  zbigmrowind = (int *)malloc(nbigm * sizeof(int));
  zbigmcolind = (int *)malloc(nbigm * sizeof(int));
  zbigmchgind = (int *)malloc(nbigm * sizeof(int));
  zbigmval = (double *)malloc(nbigm * sizeof(double));

  printf("nrows %i, nbigm %i, nbin %i, ncon %i\n", nrows, nbigm, nbin, ncon);
  for(i = 0; i < nbigm; i++)
    {
      zbigmchgind[i] = 0;
      zbigmrowind[i] = i + 1;
      zbigmcolind[i] = ncon + (int)floor(1.0*i/ncon);

      status = CPXgetcoef(env, lp, 
			  zbigmrowind[i],
			  zbigmcolind[i],
			  &zbigmval[i]);
            printf("bigm index: row [%i], col[%i], val: %f\n ",  
	     zbigmrowind[i], zbigmcolind[i],
	     zbigmval[i]);

    }

  /* Assign the allocated local memories to the original indices */

  *bigmrowind_p = zbigmrowind;
  *bigmcolind_p = zbigmcolind;
  *bigmchgind_p = zbigmchgind;

  //  CPXgetrowindex(env, lp, "resource1_scenario15 ", &colindex);
  //  CPXgetcolindex(env, lp, "y1", &rowindex);
  return 0;
}

int DZprintbigmval(CPXENVptr env, CPXLPptr lp, int *bigmrowind, int *bigmcolind)
{
  int i, status;
  int nrows = CPXgetnumrows(env, lp);
  int nbigm = nrows -1 ;
  double *bigmval = (double *)malloc(nbigm * sizeof(double));
  double *slack = (double *)malloc(nbigm * sizeof(double));
  //  CPXgetcoef(env, lp, nrow, ncol);
  printf("nbigm is %d\n", nbigm);
  status = CPXgetslack(env, lp, slack, 1, nbigm);

  for(i = 0; i < nbigm; i++)
    {
      status = CPXgetcoef(env, lp, 
			  bigmrowind[i],
			  bigmcolind[i],
			  &bigmval[i]);
      
      printf("bigm index: row [%i], col[%i], val: %f\n ",  
	     bigmrowind[i], bigmcolind[i],
	     bigmval[i]);
    }
  free(bigmval);
  free(slack);
  return 0;
}

int DZsetbigmval(CPXENVptr env, CPXLPptr lp, int *bigmrowind, int *bigmcolind)
{
  int i, status;
  int nrows = CPXgetnumrows(env, lp);
  int ncols = CPXgetnumcols(env, lp);
  int nbigm = nrows -1 ;

  int nbin = CPXgetnumbin(env, lp);
  int ncon = ncols - nbin;
  int xind;
  int yind;

  double bigmval;
  double *x = (double *)malloc(ncon * sizeof(double));
  double *y = (double *)malloc(nbin * sizeof(double));
  double *rhs = (double *)malloc(nbigm * sizeof(double));
  double tol = 0.00001;
  //  status = CPXmipopt(env,lp);
  //  status = CPXprimopt(env, lp);
  //  status = CPXgetx(env, lp, x, 0, ncon-1);     //get value of x
  //  status = CPXgetx(env, lp, y, ncon, ncols-1); // get value of y

  //  printf("nbigm %i\n", nbigm);
  //  for(i = 0; i<ncon; i++) printf("x[%i] : %f\n", i, x[i]);
  //  for(i = 0; i<nbin; i++) printf("y[%i] : %f\n", i, y[i]);

  //  status = CPXgetrhs(env, lp, rhs, 1, nrows-1);

  for(i = 0; i < nbigm; i++)
    {
      status = CPXgetcoef(env, lp, bigmrowind[i], bigmcolind[i], &bigmval);

      // Naive updating 
      bigmval = bigmval * 0.1;

      xind = i % ncon;
      yind = (int)floor(1.0*i/ncon);

      // Update bigmval to cheated bigm val
      // Only update the constraint when not satisfied

      //here you cannot mupliply since bigmval could be negative
      //      if( (fabs(y[yind] - 1.0) <= tol) ) 
      // play with the extra term here could be 0.001 and -0.001
      // if +0.001 then not optimal
      //      bigmval = rhs[i] - x[xind]; 
      /*
      if(1)
	bigmval = rhs[i] - x[xind] + 0.5;
      else
	bigmval = rhs[i] - x[xind] - 0.5; 
      */
      status = CPXchgcoef(env, lp, bigmrowind[i], bigmcolind[i], bigmval);

      


    }

  free(x);
  free(y);
  free(rhs);

  return 0;
}

int DZgetbigmval(CPXENVptr env, CPXLPptr lp, int *bigmrowind, int *bigmcolind, double *bigmval)
{
  int i, status;
  int nrows = CPXgetnumrows(env, lp);
  int ncols = CPXgetnumcols(env, lp);
  int nbigm = nrows -1 ;

  for(i = 0; i < nbigm; i++)
    {
      status = CPXgetcoef(env, lp, bigmrowind[i], bigmcolind[i], &bigmval[i]);
    }

  return 0;
}

int DZchgbigmval(CPXENVptr env, CPXLPptr lp, int *bigmrowind, int *bigmcolind, int *bigmchgind)
{
  int i, status;
  int nrows = CPXgetnumrows(env, lp);
  int ncols = CPXgetnumcols(env, lp);
  int nbigm = nrows -1 ;
  int nbin = CPXgetnumbin(env, lp);
  int ncon = ncols - nbin;
  int xind;
  int yind;
  double step = 0.1;
  double *x = (double *)malloc(ncon * sizeof(double));
  double *y = (double *)malloc(nbin * sizeof(double));
  double *rhs = (double *)malloc(nbigm * sizeof(double));
  double *bigmval = (double *)malloc(nbigm * sizeof(double));
  double tol = 0.00001;
  //  status = CPXmipopt(env,lp);
  //  status = CPXgetx(env, lp, x, 0, ncon-1);     //get value of x
  //  status = CPXgetx(env, lp, y, ncon, ncols-1); // get value of y
  status = CPXgetrhs(env, lp, rhs, 1, nrows-1);
  status = DZgetbigmval(env, lp, bigmrowind, bigmcolind, bigmval);

  for(i = 0; i < nbigm; i++)
    {
      xind = nbigm % ncon;
      if(bigmchgind[i] == 1)
	status = CPXchgcoef(env, lp, bigmrowind[i], bigmcolind[i], min(bigmval[i]*(1 + step), rhs[i] + tol));
    }

  free(x);
  free(y);
  free(rhs);
  free(bigmval);
  return 0;
}

int DZgetconind(CPXENVptr env, CPXLPptr lp, CONINFOptr cp)
{
  return 0;

}

int DZsetconbds(CPXENVptr env, CPXLPptr lp, CONINFOptr cp)
{
  int i;
  int ncon = cp->ncon;
  double initlb = 10.0;
  int status;
  for(i = 0; i < ncon; i++)
    {
      status = CPXchgbds(env, lp, 1, &i, "L", &initlb);
    }

  return 0;
}


int DZchgconbds(CPXENVptr env, CPXLPptr lp, CONINFOptr cp)
{
  int i;
  int ncon = cp->ncon;
  int *ind = cp->conchgbdsind;
  double lb;
  int status;
  for(i = 0; i < ncon; i++)
    {
      if(ind[i] == 1)
	{
	  status = CPXgetlb(env, lp, &lb, i, i);
	  printf("lb is %f at the %ith variable \n", lb, i);
	  lb = lb * 0.9;
	  status = CPXchgbds(env, lp, 1, &i, "L", &lb);
	}
    }
  
  return 0;

}
